package com.ruoyi.cms.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.cms.entity.domain.Model;
import com.ruoyi.cms.entity.domain.ModelLikes;
import com.ruoyi.cms.entity.req.MyLikeListReq;
import com.ruoyi.cms.entity.resp.ModelListResp;
import com.ruoyi.cms.mapper.ModelLikesMapper;
import com.ruoyi.cms.mapper.ModelMapper;
import com.ruoyi.cms.service.ModelLikesService;
import com.ruoyi.cms.service.ModelService;
import com.ruoyi.common.context.AppUserContext;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.RedisKeyEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 模型点赞服务实现
 */
@Service
@Slf4j
public class ModelLikesServiceImpl implements ModelLikesService {

    @Autowired
    private ModelLikesMapper modelLikesMapper;
    @Autowired
    private ModelMapper modelMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private ModelService modelService;

    /**
     * 点赞
     */
    @Override
    @Transactional
    public R<Integer> like(Long modelId) {
        Long userId = AppUserContext.getUser().getUserId();

        Set<Long> likeSet = getLikeList();

        if (likeSet.contains(modelId)) {
            return R.ok(1, "您已点赞过");
        }

        ModelLikes modelLikes = new ModelLikes();
        modelLikes.setModelId(modelId);
        modelLikes.setUserId(userId);
        modelLikes.setCreateTime(new Date());
        modelLikes.setUpdateTime(new Date());
        modelLikesMapper.insert(modelLikes);

        modelMapper.addLikeNum(modelId);

        redisCache.setCacheSet(RedisKeyEnum.CMS_MODEL_LIKE_USER.getPrefix() + userId, Collections.singleton(modelId));

        long incr = redisCache.incr(RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getPrefix() + modelId, 1);
        if (incr == 1L) {
            redisCache.expire(RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getPrefix() + modelId, RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getTimeout(),
                    RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getTimeUnit());
        }

        return R.ok(1);
    }

    /**
     * 取消点赞
     */
    @Override
    @Transactional
    public R<Integer> cancelLike(Long modelId) {
        Long userId = AppUserContext.getUser().getUserId();

        Set<Long> likeSet = getLikeList();

        if (!likeSet.contains(modelId)) {
            return R.ok(0, "您未点赞过");
        }

        LambdaQueryWrapper<ModelLikes> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ModelLikes::getModelId, modelId);
        queryWrapper.eq(ModelLikes::getUserId, userId);
        modelLikesMapper.delete(queryWrapper);

        modelMapper.subtractLikeNum(modelId);

        redisCache.deleteCacheSet(RedisKeyEnum.CMS_MODEL_LIKE_USER.getPrefix() + userId, modelId);

        redisCache.incr(RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getPrefix() + modelId, -1);

        return R.ok();
    }

    /**
     * 获取模型点赞数
     */
    @Override
    public Integer getLikeNum(Long modelId) {
        Long likeNum = redisCache.getCacheObject(RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getPrefix() + modelId);
        if (null == likeNum) {
            Model model = modelMapper.selectOne(new LambdaQueryWrapper<Model>().eq(Model::getId, modelId));
            likeNum = Long.valueOf(model.getLikeNum());
            redisCache.setCacheObject(RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getPrefix() + modelId, likeNum,
                    RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getTimeout(),
                    RedisKeyEnum.CMS_MODEL_LIKE_COUNT.getTimeUnit());
        }

        return Math.toIntExact(likeNum);
    }

    /**
     * 获取点赞列表
     */
    @Override
    public Set<Long> getLikeList() {
        Long userId = AppUserContext.getUser().getUserId();

        Set<Long> likeSet = redisCache.getCacheSet(RedisKeyEnum.CMS_MODEL_LIKE_USER.getPrefix() + userId);

        if (CollUtil.isEmpty(likeSet)) {
            LambdaQueryWrapper<ModelLikes> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ModelLikes::getUserId, userId);
            List<ModelLikes> modelLikes = modelLikesMapper.selectList(queryWrapper);

            likeSet = CollUtil.emptyIfNull(modelLikes).stream().map(ModelLikes::getModelId).collect(Collectors.toSet());

            if (CollUtil.isEmpty(likeSet)) {
                likeSet.add(-1L);
            }

            redisCache.setCacheSet(RedisKeyEnum.CMS_MODEL_LIKE_USER.getPrefix() + userId, likeSet);
            redisCache.expire(RedisKeyEnum.CMS_MODEL_LIKE_USER.getPrefix() + userId, RedisKeyEnum.CMS_MODEL_LIKE_USER.getTimeout(),
                    RedisKeyEnum.CMS_MODEL_LIKE_USER.getTimeUnit());
        }

        return likeSet;
    }

    @Override
    public R<Page<ModelListResp>> myLikeList(MyLikeListReq req) {
        Long userId = AppUserContext.getUser().getUserId();
        req.setUserId(userId);

        Page<Model> page = new Page<>(req.getCurrent(), req.getSize());

        page = modelLikesMapper.selectLikeList(req, page);

        Page<ModelListResp> modelListRespPage = (Page<ModelListResp>) page.convert(model -> {
            ModelListResp modelListResp = new ModelListResp();
            ModelListResp.ModelDetail modelDetail = modelListResp.getModelDetail();

            modelDetail.setId(model.getId());
            modelDetail.setName(model.getName());
            modelDetail.setCoverPhotoUrl(model.getCoverPhotoUrl());
            modelDetail.setCreator(model.getCreator());
            modelDetail.setLikeNum(model.getLikeNum());
            modelDetail.setCreateTime(model.getCreateTime());

            modelListResp.setModelAuthorInfo(modelService.convertAuthorInfo(model.getCreator()));

            return modelListResp;
        });

        return R.ok(modelListRespPage);
    }


}
